package ffte.evaluate.cases

import java.io.FileWriter
import java.text.SimpleDateFormat
import java.util.Date

import ffte.default.core
import ffte.property.getFFTIW

/**
 * FFT Simulation Framework Trait
 *
 * Provides a comprehensive testing framework for FFT implementations with configurable
 * parameters, test vector generation, and validation capabilities. This trait serves as
 * the foundation for testing different FFT algorithms and hardware implementations.
 *
 * Features:
 * - Configurable FFT size, scaling, and test parameters
 * - Automatic test vector generation from reference implementations
 * - Test execution control with failure tracking
 * - Logging and debugging capabilities
 * - Support for both forward and inverse FFT testing
 *
 * @example
 * class MyFFTSimulation extends Sim {
 *   N = 64      // 64-point FFT
 *   S = 10      // 10-bit scaling
 *   inv = false // Forward FFT
 *
 *   val success = done {
 *     setupFFT()
 *   } {
 *     runSingleTest()
 *   }
 * }
 *
 * @see [[ffte.evaluate.cases.FFTCase]] for specific FFT test case implementations
 */
trait Sim {
    /** FFT size (must be power of 2) */
    var N       = 2

    /** Scaling shift value for fixed-point arithmetic */
    var S       = 0

    /** Test vector index selection */
    var K       = 0

    /** Test case count per iteration */
    var CC      = 30

    /** Maximum number of test iterations */
    var C       = 1000

    /** Overall test success flag */
    var ok      = true

    /** Individual test success flag */
    var ook     = true

    /** Inverse FFT mode flag */
    var inv     = false

    /** Debug output level (0 = no debug, higher = more verbose) */
    var debug   = 0

    /** Current test iteration index */
    var idx     = 0

    /** Random generation flag for test vectors */
    var rgen    = false

    /** Failure count accumulator */
    var failcnt = 0

    /**
     * Advances to the next test iteration.
     *
     * Increments the iteration counter and prepares for the next test case.
     * Should be called at the beginning of each test iteration.
     */
    def next : Unit = { idx += 1}

    /**
     * Generates test vectors for the current FFT configuration.
     *
     * Creates a list of test vectors using the reference FFT implementation
     * configured with the current parameters (N, S, inv). Each vector contains
     * input data and expected output for validation.
     *
     * @return List of test vectors with input and expected output pairs
     *
     * @see [[ffte.default.core.GlobeSetting.testvector]] for reference implementation
     */
    def test_vectors = {
        val v = core.GlobeSetting.testvector(N,S,inv)
        List.fill(CC)(v.test_vectors(K,getFFTIW()))
    }

    /**
     * Executes a complete test suite with initialization and body.
     *
     * Runs the test framework by executing initialization code once, then
     * repeatedly executing the test body for the configured number of iterations.
     * Tracks test failures and provides comprehensive reporting.
     *
     * @param initial Code to execute once before testing begins (setup phase)
     * @param body Test code to execute for each iteration (test phase)
     * @return true if all tests passed, false if any test failed
     *
     * @example
     * val success = done {
     *   // Setup: initialize FFT hardware, load twiddle factors
     *   initializeFFT()
     * } {
     *   // Test: process one test vector and validate results
     *   val vector = test_vectors(idx % CC)
     *   val result = fftProcess(vector.input)
     *   validate(result, vector.expected)
     *   next()
     * }
     */
    def done(initial: =>Unit,body: =>Unit) : Boolean = {
        initial
        while(idx<C) {
            ook = true
            body
            if(!ook) {
                println(s"failure at $idx")
                failcnt += 1
            }
        }
        ok
    }
}

/**
 * FFT Simulation Utilities Object
 *
 * Provides utility functions for FFT testing and logging functionality.
 * This object complements the Sim trait with standalone utilities for
 * test result logging and file management.
 */
object Sim {

    /**
     * Logs a timestamped message to a specified file.
     *
     * Appends a timestamped log entry to the specified file with the current
     * date and time. Useful for tracking test progress, debugging issues,
     * and maintaining test execution history.
     *
     * @param file Path to the log file (will be created if it doesn't exist)
     * @param msg Message to log (will be timestamped)
     *
     * @example
     * Sim.log2file("fft_test.log", "64-point FFT test completed successfully")
     * // Output in file: "2025-11-02 14:30:25 done:64-point FFT test completed successfully"
     *
     * @note The file is opened in append mode, so existing content is preserved
     * @throws IOException if the file cannot be written to
     */
    def log2file(file:String,msg:String) : Unit = {
        val now: Date = new Date()
        val dateFormat: SimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
        val date = dateFormat.format(now)
        val out = new FileWriter(file,true)
        val vs = date + " done:" + msg
        out.write(vs+"\n")
        out.close()
    }
}